package top.ieei.demo.dhcp;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DHCPOption implements Serializable
{
    private static final long serialVersionUID = 2L;

    private static final Logger logger;

    private final byte code;

    private final byte[] value;

    private final boolean mirror;

    private static final Object[] _OPTION_FORMATS;

    static final Map<Byte, OptionFormat> _DHO_FORMATS;

    public DHCPOption(byte code, byte[] value, boolean mirror)
    {
        if (code == 0)
        {
            throw new IllegalArgumentException("code=0 is not allowed (reserved for padding");
        }
        if (code == -1)
        {
            throw new IllegalArgumentException("code=-1 is not allowed (reserved for End Of Options)");
        }

        this.code = code;
        this.value = (value != null ? (byte[]) value.clone() : null);
        this.mirror = mirror;
    }

    public DHCPOption(byte code, byte[] value)
    {
        this(code, value, false);
    }

    public byte getCode()
    {
        return this.code;
    }

    public boolean equals(Object o)
    {
        if (o == this)
        {
            return true;
        }
        if (!(o instanceof DHCPOption))
        {
            return false;
        }
        DHCPOption opt = (DHCPOption) o;
        return (opt.code == this.code) && (opt.mirror == this.mirror) && (Arrays.equals(opt.value, this.value));
    }

    public int hashCode()
    {
        return this.code ^ Arrays.hashCode(this.value) ^ (this.mirror ? -2147483648 : 0);
    }

    public byte[] getValue()
    {
        return this.value == null ? null : (byte[]) this.value.clone();
    }

    public byte[] getValueFast()
    {
        return this.value;
    }

    public boolean isMirror()
    {
        return this.mirror;
    }

    public static final boolean isOptionAsByte(byte code)
    {
        return OptionFormat.BYTE.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public static DHCPOption newOptionAsByte(byte code, byte val)
    {
        if (!isOptionAsByte(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not byte");
        }
        return new DHCPOption(code, byte2Bytes(val));
    }

    public byte getValueAsByte() throws IllegalArgumentException
    {
        if (!isOptionAsByte(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not byte");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length != 1)
        {
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 1");
        }
        return this.value[0];
    }

    public static final boolean isOptionAsShort(byte code)
    {
        return OptionFormat.SHORT.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public short getValueAsShort() throws IllegalArgumentException
    {
        if (!isOptionAsShort(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not short");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length != 2)
        {
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 2");
        }

        return (short) ((this.value[0] & 0xFF) << 8 | this.value[1] & 0xFF);
    }

    public static final boolean isOptionAsInt(byte code)
    {
        return OptionFormat.INT.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public int getValueAsInt() throws IllegalArgumentException
    {
        if (!isOptionAsInt(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not int");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length != 4)
        {
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 4");
        }
        return (this.value[0] & 0xFF) << 24 | (this.value[1] & 0xFF) << 16 | (this.value[2] & 0xFF) << 8
                | this.value[3] & 0xFF;
    }

    public Integer getValueAsNum() throws IllegalArgumentException
    {
        if (this.value == null)
        {
            return null;
        }
        if (this.value.length == 1)
            return Integer.valueOf(this.value[0] & 0xFF);
        if (this.value.length == 2)
            return Integer.valueOf((this.value[0] & 0xFF) << 8 | this.value[1] & 0xFF);
        if (this.value.length == 4)
        {
            return Integer.valueOf((this.value[0] & 0xFF) << 24 | (this.value[1] & 0xFF) << 16
                    | (this.value[2] & 0xFF) << 8 | this.value[3] & 0xFF);
        }

        return null;
    }

    public static final boolean isOptionAsInetAddr(byte code)
    {
        return OptionFormat.INET.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public InetAddress getValueAsInetAddr() throws IllegalArgumentException
    {
        if (!isOptionAsInetAddr(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not InetAddr");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length != 4)
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 4");
        try
        {
            return InetAddress.getByAddress(this.value);
        }
        catch (UnknownHostException e)
        {
            logger.log(Level.SEVERE, "Unexpected UnknownHostException", e);
        }
        return null;
    }

    public static final boolean isOptionAsString(byte code)
    {
        return OptionFormat.STRING.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public String getValueAsString() throws IllegalArgumentException
    {
        if (!isOptionAsString(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not String");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        return DHCPPacket.bytesToString(this.value);
    }

    public static final boolean isOptionAsShorts(byte code)
    {
        return OptionFormat.SHORTS.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public short[] getValueAsShorts() throws IllegalArgumentException
    {
        if (!isOptionAsShorts(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not short[]");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length % 2 != 0)
        {
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 2*X");
        }

        short[] shorts = new short[this.value.length / 2];
        int i = 0;
        for (int a = 0; a < this.value.length; a += 2)
        {
            shorts[i] = (short) ((this.value[a] & 0xFF) << 8 | this.value[(a + 1)] & 0xFF);

            i++;
        }

        return shorts;
    }

    public static final boolean isOptionAsInetAddrs(byte code)
    {
        return OptionFormat.INETS.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public InetAddress[] getValueAsInetAddrs() throws IllegalArgumentException
    {
        if (!isOptionAsInetAddrs(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not InetAddr[]");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        if (this.value.length % 4 != 0)
        {
            throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length
                    + " should be 4*X");
        }
        try
        {
            byte[] addr = new byte[4];
            InetAddress[] addrs = new InetAddress[this.value.length / 4];
            int i = 0;
            for (int a = 0; a < this.value.length; a += 4)
            {
                addr[0] = this.value[a];
                addr[1] = this.value[(a + 1)];
                addr[2] = this.value[(a + 2)];
                addr[3] = this.value[(a + 3)];
                addrs[i] = InetAddress.getByAddress(addr);

                i++;
            }

            return addrs;
        }
        catch (UnknownHostException e)
        {
            logger.log(Level.SEVERE, "Unexpected UnknownHostException", e);
        }
        return null;
    }

    public static final boolean isOptionAsBytes(byte code)
    {
        return OptionFormat.BYTES.equals(_DHO_FORMATS.get(Byte.valueOf(code)));
    }

    public byte[] getValueAsBytes() throws IllegalArgumentException
    {
        if (!isOptionAsBytes(this.code))
        {
            throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not bytes");
        }
        if (this.value == null)
        {
            throw new IllegalStateException("value is null");
        }
        return getValue();
    }

    public static DHCPOption newOptionAsShort(byte code, short val)
    {
        if (!isOptionAsShort(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not short");
        }
        return new DHCPOption(code, short2Bytes(val));
    }

    public static DHCPOption newOptionAsShorts(byte code, short[] arr)
    {
        if (!isOptionAsShorts(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not shorts");
        }
        byte[] buf = null;
        if (arr != null)
        {
            buf = new byte[arr.length * 2];
            for (int i = 0; i < arr.length; i++)
            {
                short val = arr[i];
                buf[(i * 2)] = (byte) ((val & 0xFF00) >>> 8);
                buf[(i * 2 + 1)] = (byte) (val & 0xFF);
            }
        }
        return new DHCPOption(code, buf);
    }

    public static DHCPOption newOptionAsInt(byte code, int val)
    {
        if (!isOptionAsInt(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not int");
        }
        return new DHCPOption(code, int2Bytes(val));
    }

    public static DHCPOption newOptionAsInetAddress(byte code, InetAddress val)
    {
        if ((!isOptionAsInetAddr(code)) && (!isOptionAsInetAddrs(code)))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not InetAddress");
        }
        return new DHCPOption(code, inetAddress2Bytes(val));
    }

    public static DHCPOption newOptionAsInetAddresses(byte code, InetAddress[] val)
    {
        if (!isOptionAsInetAddrs(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not InetAddresses");
        }
        return new DHCPOption(code, inetAddresses2Bytes(val));
    }

    public static DHCPOption newOptionAsString(byte code, String val)
    {
        if (!isOptionAsString(code))
        {
            throw new IllegalArgumentException("DHCP option type (" + code + ") is not string");
        }
        return new DHCPOption(code, DHCPPacket.stringToBytes(val));
    }

    public DHCPOption applyOption(DHCPPacket request)
    {
        if (request == null)
        {
            throw new NullPointerException("request is null");
        }
        if (this.mirror)
        {
            DHCPOption res = request.getOption(getCode());
            return res != null ? res : this;
        }
        return this;
    }

    public void append(StringBuilder buffer)
    {
        if (Constants._DHO_NAMES.containsKey(Byte.valueOf(this.code)))
        {
            buffer.append((String) Constants._DHO_NAMES.get(Byte.valueOf(this.code)));
        }
        buffer.append('(').append(unsignedByte(this.code)).append(")=");

        if (this.mirror)
        {
            buffer.append("<mirror>");
        }

        if (this.value == null)
        {
            buffer.append("<null>");
        }
        else if (this.code == 53)
        {
            Byte cmd = Byte.valueOf(getValueAsByte());
            if (Constants._DHCP_CODES.containsKey(cmd))
                buffer.append((String) Constants._DHCP_CODES.get(cmd));
            else
                buffer.append(cmd);
        }
        else if (this.code == 77)
        {
            buffer.append(userClassToString(this.value));
        }
        else if (this.code == 82)
        {
            buffer.append(agentOptionsToString(this.value));
        }
        else if (_DHO_FORMATS.containsKey(Byte.valueOf(this.code)))
        {
            try
            {
                switch (_DHO_FORMATS.get(Byte.valueOf(this.code)).ordinal())
                {
                    case 1 :
                        DHCPPacket.appendHostAddress(buffer, getValueAsInetAddr());
                        break;
                    case 2 :
                        for (InetAddress addr : getValueAsInetAddrs())
                        {
                            DHCPPacket.appendHostAddress(buffer, addr);
                            buffer.append(' ');
                        }
                        break;
                    case 3 :
                        buffer.append(getValueAsInt());
                        break;
                    case 4 :
                        buffer.append(getValueAsShort());
                        break;
                    case 5 :
                        for (short aShort : getValueAsShorts())
                        {
                            buffer.append(aShort).append(' ');
                        }

                        break;
                    case 6 :
                        buffer.append(getValueAsByte());
                        break;
                    case 7 :
                        buffer.append('"').append(getValueAsString()).append('"');

                        break;
                    case 8 :
                        if (this.value == null)
                            break;
                        for (byte aValue : this.value)
                        {
                            buffer.append(unsignedByte(aValue)).append(' ');
                        }

                        break;
                    default :
                        buffer.append("0x");
                        DHCPPacket.appendHex(buffer, this.value);
                }
            }
            catch (IllegalArgumentException e)
            {
                buffer.append("0x");
                DHCPPacket.appendHex(buffer, this.value);
            }
        }
        else
        {
            buffer.append("0x");
            DHCPPacket.appendHex(buffer, this.value);
        }
    }

    public String toString()
    {
        StringBuilder s = new StringBuilder();

        append(s);
        return s.toString();
    }

    private static int unsignedByte(byte b)
    {
        return b & 0xFF;
    }

    public static byte[] byte2Bytes(byte val)
    {
        byte[] raw = {val};
        return raw;
    }

    public static byte[] short2Bytes(short val)
    {
        byte[] raw = {(byte) ((val & 0xFF00) >>> 8), (byte) (val & 0xFF)};
        return raw;
    }

    public static byte[] int2Bytes(int val)
    {
        byte[] raw = {(byte) ((val & 0xFF000000) >>> 24), (byte) ((val & 0xFF0000) >>> 16),
                (byte) ((val & 0xFF00) >>> 8), (byte) (val & 0xFF)};

        return raw;
    }

    public static byte[] inetAddress2Bytes(InetAddress val)
    {
        if (val == null)
        {
            return null;
        }
        if (!(val instanceof Inet4Address))
        {
            throw new IllegalArgumentException("Adress must be of subclass Inet4Address");
        }
        return val.getAddress();
    }

    public static byte[] inetAddresses2Bytes(InetAddress[] val)
    {
        if (val == null)
        {
            return null;
        }

        byte[] buf = new byte[val.length * 4];
        for (int i = 0; i < val.length; i++)
        {
            InetAddress addr = val[i];
            if (!(addr instanceof Inet4Address))
            {
                throw new IllegalArgumentException("Adress must be of subclass Inet4Address");
            }
            System.arraycopy(addr.getAddress(), 0, buf, i * 4, 4);
        }
        return buf;
    }

    public static List<String> userClassToList(byte[] buf)
    {
        if (buf == null)
        {
            return null;
        }

        LinkedList<String> list = new LinkedList<String>();
        int i = 0;
        while (i < buf.length)
        {
            int size = unsignedByte(buf[(i++)]);
            int instock = buf.length - i;
            if (size > instock)
            {
                size = instock;
            }
            list.add(DHCPPacket.bytesToString(buf, i, size));
            i += size;
        }
        return list;
    }

    public static String userClassToString(byte[] buf)
    {
        if (buf == null)
        {
            return null;
        }

        List<String> list = userClassToList(buf);
        Iterator<String> it = list.iterator();
        StringBuffer s = new StringBuffer();

        while (it.hasNext())
        {
            s.append('"').append((String) it.next()).append('"');
            if (it.hasNext())
            {
                s.append(',');
            }
        }
        return s.toString();
    }

    public static byte[] stringListToUserClass(List<String> list)
    {
        if (list == null)
            return null;

        ByteArrayOutputStream buf = new ByteArrayOutputStream(32);
        DataOutputStream out = new DataOutputStream(buf);
        try
        {
            for (String s : list)
            {
                byte[] bytes = DHCPPacket.stringToBytes(s);
                int size = bytes.length;

                if (size > 255)
                    size = 255;
                out.writeByte(size);
                out.write(bytes, 0, size);
            }
            return buf.toByteArray();
        }
        catch (IOException e)
        {
            logger.log(Level.SEVERE, "Unexpected IOException", e);
        }
        return buf.toByteArray();
    }

    public static String agentOptionsToString(byte[] buf)
    {
        if (buf == null)
        {
            return null;
        }

        Map<Byte, String> map = agentOptionsToMap(buf);
        StringBuffer s = new StringBuffer();
        for (Map.Entry<Byte, String> entry : map.entrySet())
        {
            s.append('{').append(unsignedByte(((Byte) entry.getKey()).byteValue())).append("}\"");
            s.append((String) entry.getValue()).append('"');
            s.append(',');
        }
        if (s.length() > 0)
        {
            s.setLength(s.length() - 1);
        }

        return s.toString();
    }

    public static byte[] agentOptionToRaw(Map<Byte, String> map)
    {
        if (map == null)
        {
            return null;
        }
        ByteArrayOutputStream buf = new ByteArrayOutputStream(64);
        DataOutputStream out = new DataOutputStream(buf);
        try
        {
            for (Map.Entry<Byte, String> entry : map.entrySet())
            {
                byte[] bufTemp = DHCPPacket.stringToBytes((String) entry.getValue());
                int size = bufTemp.length;
                assert (size >= 0);
                if (size > 255)
                {
                    throw new IllegalArgumentException("Value size is greater then 255 bytes");
                }
                out.writeByte(((Byte) entry.getKey()).byteValue());
                out.writeByte(size);
                out.write(bufTemp, 0, size);
            }
            return buf.toByteArray();
        }
        catch (IOException e)
        {
            logger.log(Level.SEVERE, "Unexpected IOException", e);
        }
        return buf.toByteArray();
    }

    public static final Map<Byte, String> agentOptionsToMap(byte[] buf)
    {
        if (buf == null)
        {
            return null;
        }

        Map<Byte, String> map = new LinkedHashMap<Byte, String>();
        int i = 0;

        while ((i < buf.length) && (buf.length - i >= 2))
        {
            Byte key = Byte.valueOf(buf[(i++)]);
            int size = unsignedByte(buf[(i++)]);
            int instock = buf.length - i;

            if (size > instock)
            {
                size = instock;
            }
            map.put(key, DHCPPacket.bytesToString(buf, i, size));
            i += size;
        }
        return map;
    }

    public static Class<?> getOptionFormat(byte code)
    {
        OptionFormat format = (OptionFormat) _DHO_FORMATS.get(Byte.valueOf(code));
        if (format == null)
        {
            return null;
        }
        switch (format.ordinal())
        {
            case 1 :
                return InetAddress.class;
            case 2 :
                return InetAddress.class;
            case 3 :
                return Integer.TYPE;
            case 4 :
                return Short.TYPE;
            case 5 :
                return Short.class;
            case 6 :
                return Byte.TYPE;
            case 8 :
                return Byte.class;
            case 7 :
                return String.class;
        }
        return null;
    }

    public static Class<?> string2Class(String className)
    {
        if ("InetAddress".equals(className))
            return InetAddress.class;
        if ("inet".equals(className))
            return InetAddress.class;
        if ("InetAddress[]".equals(className))
            return InetAddress.class;
        if ("inets".equals(className))
            return InetAddress.class;
        if ("int".equals(className))
            return Integer.TYPE;
        if ("short".equals(className))
            return Short.TYPE;
        if ("short[]".equals(className))
            return Short.class;
        if ("shorts".equals(className))
            return Short.class;
        if ("byte".equals(className))
            return Byte.TYPE;
        if ("byte[]".equals(className))
            return Byte.class;
        if ("bytes".equals(className))
            return Byte.class;
        if ("String".equals(className))
            return String.class;
        if ("string".equals(className))
            return String.class;
        return null;
    }

    public static DHCPOption parseNewOption(byte code, Class<?> format, String value)
    {
        if ((format == null) || (value == null))
        {
            throw new NullPointerException();
        }

        if (Short.TYPE.equals(format))
            return newOptionAsShort(code, (short) Integer.parseInt(value));
        if (Short.class.equals(format))
        {
            String[] listVal = value.split(" ");
            short[] listShort = new short[listVal.length];
            for (int i = 0; i < listVal.length; i++)
            {
                listShort[i] = (short) Integer.parseInt(listVal[i]);
            }
            return newOptionAsShorts(code, listShort);
        }
        if (Integer.TYPE.equals(format))
            return newOptionAsInt(code, Integer.parseInt(value));
        if (String.class.equals(format))
            return newOptionAsString(code, value);
        if (Byte.TYPE.equals(format))
        {
            return newOptionAsByte(code, (byte) Integer.parseInt(value));
        }
        if (Byte.class.equals(format))
        {
            value = value.replace(".", " ");
            String[] listVal = value.split(" ");
            byte[] listBytes = new byte[listVal.length];
            for (int i = 0; i < listVal.length; i++)
            {
                listBytes[i] = (byte) Integer.parseInt(listVal[i]);
            }
            return new DHCPOption(code, listBytes);
        }
        if (InetAddress.class.equals(format))
            try
            {
                return newOptionAsInetAddress(code, InetAddress.getByName(value));
            }
            catch (UnknownHostException e)
            {
                logger.log(Level.SEVERE, "Invalid address:" + value, e);
                return null;
            }
        if (InetAddress.class.equals(format))
        {
            String[] listVal = value.split(" ");
            InetAddress[] listInet = new InetAddress[listVal.length];
            try
            {
                for (int i = 0; i < listVal.length; i++)
                    listInet[i] = InetAddress.getByName(listVal[i]);
            }
            catch (UnknownHostException e)
            {
                logger.log(Level.SEVERE, "Invalid address", e);
                return null;
            }
            return newOptionAsInetAddresses(code, listInet);
        }
        return null;
    }

    static enum OptionFormat
    {
        INET, INETS, INT, SHORT, SHORTS, BYTE, BYTES, STRING;
    }

    static
    {
        logger = Logger.getLogger(DHCPOption.class.getName().toLowerCase());

        _OPTION_FORMATS = new Object[]{Byte.valueOf((byte) 1), OptionFormat.INET, Byte.valueOf((byte) 2),
                OptionFormat.INT, Byte.valueOf((byte) 3), OptionFormat.INETS, Byte.valueOf((byte) 4),
                OptionFormat.INETS, Byte.valueOf((byte) 5), OptionFormat.INETS, Byte.valueOf((byte) 6),
                OptionFormat.INETS, Byte.valueOf((byte) 7), OptionFormat.INETS, Byte.valueOf((byte) 8),
                OptionFormat.INETS, Byte.valueOf((byte) 9), OptionFormat.INETS, Byte.valueOf((byte) 10),
                OptionFormat.INETS, Byte.valueOf((byte) 11), OptionFormat.INETS, Byte.valueOf((byte) 12),
                OptionFormat.STRING, Byte.valueOf((byte) 13), OptionFormat.SHORT, Byte.valueOf((byte) 14),
                OptionFormat.STRING, Byte.valueOf((byte) 15), OptionFormat.STRING, Byte.valueOf((byte) 16),
                OptionFormat.INET, Byte.valueOf((byte) 17), OptionFormat.STRING, Byte.valueOf((byte) 18),
                OptionFormat.STRING, Byte.valueOf((byte) 19), OptionFormat.BYTE, Byte.valueOf((byte) 20),
                OptionFormat.BYTE, Byte.valueOf((byte) 21), OptionFormat.INETS, Byte.valueOf((byte) 22),
                OptionFormat.SHORT, Byte.valueOf((byte) 23), OptionFormat.BYTE, Byte.valueOf((byte) 24),
                OptionFormat.INT, Byte.valueOf((byte) 25), OptionFormat.SHORTS, Byte.valueOf((byte) 26),
                OptionFormat.SHORT, Byte.valueOf((byte) 27), OptionFormat.BYTE, Byte.valueOf((byte) 28),
                OptionFormat.INET, Byte.valueOf((byte) 29), OptionFormat.BYTE, Byte.valueOf((byte) 30),
                OptionFormat.BYTE, Byte.valueOf((byte) 31), OptionFormat.BYTE, Byte.valueOf((byte) 32),
                OptionFormat.INET, Byte.valueOf((byte) 33), OptionFormat.INETS, Byte.valueOf((byte) 34),
                OptionFormat.BYTE, Byte.valueOf((byte) 35), OptionFormat.INT, Byte.valueOf((byte) 36),
                OptionFormat.BYTE, Byte.valueOf((byte) 37), OptionFormat.BYTE, Byte.valueOf((byte) 38),
                OptionFormat.INT, Byte.valueOf((byte) 39), OptionFormat.BYTE, Byte.valueOf((byte) 41),
                OptionFormat.INETS, Byte.valueOf((byte) 42), OptionFormat.INETS, Byte.valueOf((byte) 44),
                OptionFormat.INETS, Byte.valueOf((byte) 45), OptionFormat.INETS, Byte.valueOf((byte) 46),
                OptionFormat.BYTE, Byte.valueOf((byte) 47), OptionFormat.STRING, Byte.valueOf((byte) 48),
                OptionFormat.INETS, Byte.valueOf((byte) 49), OptionFormat.INETS, Byte.valueOf((byte) 50),
                OptionFormat.INET, Byte.valueOf((byte) 51), OptionFormat.INT, Byte.valueOf((byte) 52),
                OptionFormat.BYTE, Byte.valueOf((byte) 53), OptionFormat.BYTE, Byte.valueOf((byte) 54),
                OptionFormat.INET, Byte.valueOf((byte) 55), OptionFormat.BYTES, Byte.valueOf((byte) 56),
                OptionFormat.STRING, Byte.valueOf((byte) 57), OptionFormat.SHORT, Byte.valueOf((byte) 58),
                OptionFormat.INT, Byte.valueOf((byte) 59), OptionFormat.INT, Byte.valueOf((byte) 60),
                OptionFormat.STRING, Byte.valueOf((byte) 62), OptionFormat.STRING, Byte.valueOf((byte) 64),
                OptionFormat.STRING, Byte.valueOf((byte) 65), OptionFormat.STRING, Byte.valueOf((byte) 66),
                OptionFormat.STRING, Byte.valueOf((byte) 67), OptionFormat.STRING, Byte.valueOf((byte) 68),
                OptionFormat.INETS, Byte.valueOf((byte) 69), OptionFormat.INETS, Byte.valueOf((byte) 70),
                OptionFormat.INETS, Byte.valueOf((byte) 71), OptionFormat.INETS, Byte.valueOf((byte) 72),
                OptionFormat.INETS, Byte.valueOf((byte) 73), OptionFormat.INETS, Byte.valueOf((byte) 74),
                OptionFormat.INETS, Byte.valueOf((byte) 75), OptionFormat.INETS, Byte.valueOf((byte) 76),
                OptionFormat.INETS, Byte.valueOf((byte) 85), OptionFormat.INETS, Byte.valueOf((byte) 86),
                OptionFormat.STRING, Byte.valueOf((byte) 87), OptionFormat.STRING, Byte.valueOf((byte) 91),
                OptionFormat.INT, Byte.valueOf((byte) 92), OptionFormat.INETS, Byte.valueOf((byte) 98),
                OptionFormat.STRING, Byte.valueOf((byte) 116), OptionFormat.BYTE, Byte.valueOf((byte) 117),
                OptionFormat.SHORTS, Byte.valueOf((byte) 118), OptionFormat.INET, Byte.valueOf((byte) 119),
                OptionFormat.STRING};

        _DHO_FORMATS = new LinkedHashMap<Byte, OptionFormat>();

        for (int i = 0; i < _OPTION_FORMATS.length / 2; i++)
            _DHO_FORMATS.put((Byte) _OPTION_FORMATS[(i * 2)], (OptionFormat) _OPTION_FORMATS[(i * 2 + 1)]);
    }

}